import scheduleUpdateOnFiber from '../reconciler/ReactFiberWorkLoop';
import { areHookInputEqual } from '../shared/utils';

let currentlyRenderingFiber = null; // 当前渲染的 fiber 对象
let workInProgressHook = null; // 当前正在处理的 hook
let currentHook = null; // 当前处理完的 hook

export function renderWithHooks(wip) {
  currentlyRenderingFiber = wip;
  workInProgressHook = null;
  currentlyRenderingFiber.memorizedState = null;
  currentlyRenderingFiber.updateQueue = [];
}

function updateWorkInProgressHook() {
  let hook = null;
  const current = currentlyRenderingFiber.alternate;

  if (current) {
    currentlyRenderingFiber.memorizedState = current.memorizedState;
    if (workInProgressHook) {
      workInProgressHook = hook = workInProgressHook.next;
      currentHook = currentHook.next;
    } else {
      workInProgressHook = hook = currentlyRenderingFiber.memorizedState;
      currentHook = currentlyRenderingFiber.memorizedState;
    }
  } else {
    hook = {
      memorizedState: null,
      next: null,
    };
    if (workInProgressHook) {
      workInProgressHook = workInProgressHook.next = hook;
    } else {
      workInProgressHook = currentlyRenderingFiber.memorizedState = hook;
    }
  }

  return hook;
}

function dispatchReducerAction(fiber, hook, reducer, action) {
  fiber.memorizedState = reducer ? reducer(hook.memorizedState, action) : action;

  fiber.alternate = {
    ...fiber,
  };
  fiber.sibling = null;
  scheduleUpdateOnFiber(fiber);
}

export function useState(initialState) {
  return useReducer(null, initialState);
}

export function useReducer(reducer, initialState) {
  const hook = updateWorkInProgressHook();

  if (!currentlyRenderingFiber.alternate) {
    hook.memorizedState = initialState;
  }

  const dispatch = dispatchReducerAction.bind(
    null,
    currentlyRenderingFiber,
    hook,
    reducer
  );

  return [hook.memorizedState, dispatch];
}

export function useEffect(create, deps) {
  const hook = updateWorkInProgressHook();
  let destroy = null;

  if (currentHook) {
    const prevEffect = currentHook.memorizedState;
    destroy = prevEffect.destroy;
    const prevDeps = prevEffect.deps;
    if (deps) {
      if (areHookInputEqual(deps, prevDeps)) {
        return;
      }
    }
  }

  const effect = {
    create,
    deps,
    destroy,
  };

  currentlyRenderingFiber.updateQueue.push(effect);
}
